package org.zh.util;

import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

public class ComponentScan {
    public static List<Class<?>> run(Class<?> application) throws IOException {
        String[] split = System.getProperty("java.class.path").split(File.pathSeparator);
        List<Class<?>> list = new ArrayList<>();
        String packageName = "org.zh";
        for (String path : split) {
            if (path.endsWith(".jar") && !packageName.isEmpty()) {
                list.addAll(findClassesInJar(packageName, path, new ArrayList<>()));
            } else {
                list.addAll(findClassesInDirectory(packageName, path, new ArrayList<>()));
            }
        }
        return list;
    }

    private static List<Class<?>> findClassesInJar(String packageName, String directory, List<Class<?>> classes) throws IOException {
        Path jarPath = Paths.get(directory);
        java.nio.file.FileSystem fs = FileSystems.newFileSystem(jarPath);
        Path root = fs.getPath("/");
        Files.walk(root)
                .filter(path1 -> path1.toString().endsWith(".class") && !path1.startsWith("/META-INF") && !path1.endsWith("module-info.class") && !path1.endsWith("package-info.class"))
                .map(path -> path.toString().split(".class")[0].replace("/", ".").substring(1))
                .filter(name -> name.startsWith(packageName))
                .map(name -> {
                    try {
                        return Class.forName(name, false, Thread.currentThread().getContextClassLoader());
                    } catch (ClassNotFoundException e) {
                        throw new RuntimeException(e);
                    }
                }).forEach(classes::add);
        return classes;
    }


    private static List<Class<?>> findClassesInDirectory(String packageName, String directory, List<Class<?>> classes) throws IOException {
        Path path = Paths.get(directory);
        Files.walk(path).filter(path1 -> path1.toString().endsWith(".class"))
                .map(pathc -> pathc.toString().split("classes")[1].replace("\\", ".").substring(1).split(".class")[0])
                .filter(name -> name.startsWith(packageName))
                .map(name -> {
                    try {
                        return Class.forName(name, false, Thread.currentThread().getContextClassLoader());
                    } catch (ClassNotFoundException e) {
                        throw new RuntimeException(e);
                    }
                }).forEach(classes::add);
        return classes;

    }

}
